package com.smart.manager.member.repository;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.*;
import com.alicp.jetcache.Cache;
import com.smart.common.cache.CacheService;
import com.smart.common.config.satoken.LocalContextClient;
import com.smart.common.entities.constant.ArcoTips;
import com.smart.common.entities.constant.SmartConstant;
import com.smart.common.entities.core.Page;
import com.smart.common.exception.SmartException;
import com.smart.manager.member.entities.assembler.MemberSimple;
import com.smart.manager.member.entities.bodys.RMemberMaterialProps;
import com.smart.manager.member.entities.bodys.RMemberProfileMain;
import com.smart.manager.member.entities.enums.MemberLevel;
import com.smart.manager.member.entities.enums.PropsKind;
import com.smart.manager.member.entities.models.MemberMaterialPig;
import com.smart.manager.member.entities.models.MemberProfileMain;
import com.smart.manager.member.entities.models.query.QMemberMaterialPig;
import com.smart.manager.member.entities.models.query.QMemberProfileMain;
import com.smart.manager.member.entities.views.MemberPigView;
import com.smart.manager.member.entities.views.MemberView;
import com.smart.manager.member.entities.views.query.QMemberView;
import com.smart.manager.pop.entities.views.InviterView;
import com.smart.manager.pop.entities.views.query.QInviterView;
import com.smart.manager.product.entities.enums.PigStatus;
import com.smart.manager.product.entities.enums.PigstyKind;
import com.smart.manager.product.entities.enums.ServeTask;
import com.smart.manager.product.entities.models.BasicRfid;
import com.smart.manager.product.entities.models.PigGoods;
import com.smart.manager.product.entities.models.PigLevel;
import com.smart.manager.product.entities.models.PropsServe;
import com.smart.manager.product.entities.models.query.QBasicRfid;
import com.smart.manager.product.entities.models.query.QPigGoods;
import com.smart.manager.product.entities.models.query.QPigLevel;
import com.smart.manager.product.entities.models.query.QPropsServe;
import com.smart.manager.product.entities.views.BasicRfidView;
import com.smart.manager.product.entities.views.PigLevelView;
import com.smart.manager.product.entities.views.PropsComboView;
import com.smart.manager.product.entities.views.query.QPropsComboView;
import com.smart.manager.work.entities.assembler.WorkOrder;
import com.smart.manager.work.entities.enums.PigOrderKind;
import com.smart.manager.work.entities.enums.PigOrderStatus;
import com.smart.manager.work.entities.models.PigOrder;
import com.smart.manager.work.entities.models.query.QPigOrder;
import com.smart.manager.work.entities.models.query.QTaskMain;
import com.smart.manager.work.repository.PigOrderRepository;
import com.smart.utils.MemberAcl;
import com.smart.utils.MemberUtil;
import com.smart.utils.SqlUtil;
import com.smart.wap.service.BatchService;
import io.ebean.DB;
import io.ebean.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Administrator
 */
@Service
@Log4j2
@RequiredArgsConstructor
public class MemberProfileMainRepository {

    private final CacheService cacheService;
    private final MemberAccountRepository accountRepository;
    private final MemberMaterialPropsRepository memberMaterialPropsRepository;
    private final PigOrderRepository pigOrderRepository;


    private final BatchService batchService;


    public Page<MemberProfileMain> pageList(RMemberProfileMain.SearchBody search) {
        QMemberProfileMain query = new QMemberProfileMain();
        Opt.ofNullable(search.getRealAttr()).ifPresent(x -> query.realAttr.eq(x));
        Opt.ofNullable(search.getSex()).ifPresent(x -> query.sex.eq(x));
        Opt.ofNullable(search.getLevel()).ifPresent(x -> query.level.eq(x));
        Opt.ofBlankAble(search.getOrigin()).ifPresent(x -> query.origin.eq(x));
        Opt.ofBlankAble(search.getNickName()).ifPresent(x -> query.nickName.contains(x));
        Opt.ofBlankAble(search.getPhoneNumber()).ifPresent(x -> query.phoneNumber.contains(x));
        Opt.ofBlankAble(search.getDateRange()).ifPresent(x -> {
            LocalDateTime[] times = SqlUtil.formatDateTimeRange(x);
            query.regTime.between(times[0], times[1]);
        });
        Opt.ofNullable(search.getFirmAttr()).ifPresent(x -> query.firmAttr.jsonEqualTo("checked", x));
        query.order().id.desc();
        query.setFirstRow(search.firstRow()).setMaxRows(search.maxRows());
        Page<MemberProfileMain> load = new Page<MemberProfileMain>().load(query.findPagedList());


        Set<Long> b2c = load.getRecords().stream().filter(x -> {
            return ObjUtil.isNotNull(x.getInviteMode()) && x.getInviteMode().equals("B2C");
        }).map(MemberProfileMain::getInviterId).collect(Collectors.toSet());
        Map<Long, InviterView> b2cMap = new QInviterView().id.in(b2c).findStream()
                .collect(Collectors.toMap(InviterView::getId, Function.identity()));


        Set<Long> c2c = load.getRecords().stream().filter(x -> {
            return ObjUtil.isNotNull(x.getInviteMode()) && x.getInviteMode().equals("C2C");
        }).map(MemberProfileMain::getInviterId).collect(Collectors.toSet());
        Map<Long, MemberView> c2cMap = new QMemberView().id.in(c2c).findStream()
                .collect(Collectors.toMap(MemberView::getId, Function.identity()));


        load.getRecords().forEach(x -> {
            if (ObjUtil.isNotNull(x.getInviteMode())) {
                if (x.getInviteMode().equals("B2C")) {
                    x.setInviterInfo(ObjUtil.defaultIfNull(b2cMap.get(x.getInviterId()),""));
                }
                if (x.getInviteMode().equals("C2C")) {
                    x.setInviterInfo(ObjUtil.defaultIfNull(c2cMap.get(x.getInviterId()),""));
                }
            }
        });
        return load;
    }

    public void add(RMemberProfileMain.EditBody body) {
        MemberProfileMain record = getOneByPhoneNumber(body.getPhoneNumber());
        if (ObjUtil.isNotNull(record)) {
            if (record.getRealAttr().equals(Boolean.FALSE)) {
                removeMember(record);
            } else {
                throw new SmartException("企业会员添加失败: 手机号码已被注册过了");
            }
        }
        MemberProfileMain insRecord = MemberUtil.generate();
        //刷新注册会员的
        String nickName = getRandomName();
        insRecord.setNickName(nickName).setAvatar(StrUtil.EMPTY).setRealAttr(true).setLevel(MemberLevel.L4).setPhoneNumber(body.getPhoneNumber());
        insRecord.getFirmAttr().setIsGetPig(!body.getIsPig()).setPigGoodsCode(body.getPigGoodsCode()).setPig(body.getPig()).setChecked(true).setReadyName(body.getReadyName()).setCompanyName(body.getCompanyName());
        insRecord.save();
        //初始化会员账户
        accountRepository.initAccount(insRecord.getId());

    }


    @Async
    public void delPigInfo(Long memberId) {
        //猪仔
        List<MemberMaterialPig> materialPigs = new QMemberMaterialPig().member.id.eq(memberId).findList();
        List<Long> pigIds = materialPigs.stream().map(MemberMaterialPig::getId).collect(Collectors.toList());
        List<String> pigCodes = materialPigs.stream().map(MemberMaterialPig::getCode).collect(Collectors.toList());

        //耳标
        List<String> rfidCodes = materialPigs.stream().map(MemberMaterialPig::getRfid).filter(ObjUtil::isNotNull).map(BasicRfidView::getBeaconMac).collect(Collectors.toList());
        List<BasicRfid> rfidList = new QBasicRfid().beaconMac.in(rfidCodes).findList();
        //工单
        List<PigOrder> pigOrders = new QPigOrder().pig.id.in(pigIds).findList();
        //
        new QTaskMain().orders.id.in(pigOrders.stream().map(PigOrder::getId).collect(Collectors.toList())).delete();
        try {
            //删除喂食
            String sql0 = "DELETE FROM member_material_pig_plan WHERE member = " + memberId;
            DB.sqlUpdate(sql0).execute();

            //删除背包
            String sql1 = "DELETE FROM member_material_props WHERE member = " + memberId;
            DB.sqlUpdate(sql1).execute();

            //删除喂食工单
            for (String pigCode : pigCodes) {
                String sql = "UPDATE work_pig_order_foods SET pig_code_list = array_remove(pig_code_list, '" + pigCode + "') WHERE '" + pigCode + "' = ANY (pig_code_list);";
                DB.sqlUpdate(sql).execute();
            }
            //删除猪仔
            DB.deleteAll(materialPigs);
            //删除猪仔耳标
            DB.deleteAll(rfidList);
            //删除猪仔工单
            DB.deleteAll(pigOrders);
        } catch (Exception e) {
            log.error("格式化失败!");
            e.printStackTrace();
        }
    }


    public void addPop(String phoneNumber) {
        MemberProfileMain record = getOneByPhoneNumber(phoneNumber);
        if (ObjUtil.isNotNull(record)) {
            if (record.getRealAttr().equals(Boolean.FALSE)) {
                removeMember(record);
            } else {
                throw new SmartException("手机号码已被注册过了");
            }
        }
        MemberProfileMain insRecord = MemberUtil.generate();
        //刷新注册会员的
        String nickName = getRandomName();
        insRecord.setNickName(nickName).setAvatar(StrUtil.EMPTY).setRealAttr(true).setLevel(MemberLevel.L2);
        insRecord.save();
        //初始化会员账户
        accountRepository.initAccount(insRecord.getId());
    }


    public void update(Long id, RMemberProfileMain.EditBody body) {
        QMemberProfileMain query = new QMemberProfileMain();
        MemberProfileMain record = query.id.eq(id).setMaxRows(1).findOne();
        Assert.notNull(record, ArcoTips.UPDATE_NOT_FOUND);
        record.getFirmAttr().setCompanyName(body.getCompanyName()).setReadyName(body.getReadyName());
        Objects.requireNonNull(record).update();
    }

    public void updateRemarks(Long id, RMemberProfileMain.RemarksBody body) {
        QMemberProfileMain query = new QMemberProfileMain();
        MemberProfileMain record = query.id.eq(id).setMaxRows(1).findOne();
        Assert.notNull(record, ArcoTips.UPDATE_NOT_FOUND);
        record.setRemarks(body.getContent());
        Objects.requireNonNull(record).update();
    }

    public int delByIds(List<Long> ids) {
        List<MemberProfileMain> list = new QMemberProfileMain().realAttr.eq(false).id.in(ids).findList();
        Assert.notEmpty(list, ArcoTips.DELETE_NOT_FOUND);
        return DB.deleteAll(list);
    }


    /**
     * 生成虚拟会员
     *
     * @param body 身体
     */
    @Async
    public void generated(RMemberProfileMain.GeneratedBody body) {
        ArrayList<MemberProfileMain> insArr = new ArrayList<>();
        for (int i = 0; i < body.getCount(); i++) {
            String nickName = getRandomName();
            MemberProfileMain generate = MemberUtil.generate();
            generate.setNickName(nickName);
            insArr.add(generate);
        }
        Opt.ofEmptyAble(insArr).ifPresent(DB::insertAll);
    }


    @Async
    public void removeMember(MemberProfileMain memberProfileMain) {
        memberProfileMain.delete();
    }


    /**
     * 生成随机昵称
     *
     * @return {@code String}
     */
    public String getRandomName() {
        return SmartConstant.NICKNAME_PREFIX.concat(RandomUtil.randomNumbers(6));
    }


    /**
     * @param phoneNumber 根据手机号码查询会员资料是否存在
     * @return {@code MemberProfileMain}
     */
    public MemberProfileMain getOneByPhoneNumber(String phoneNumber) {
        return new QMemberProfileMain().phoneNumber.eq(phoneNumber).setMaxRows(1).findOne();
    }


    /**
     * 获取会员简单信息
     *
     * @param memberId
     * @return
     */
    public MemberSimple readSimple(Long memberId, boolean checkNull) {
        Cache<Long, MemberSimple> memberCache = cacheService.getMemberCache();
        MemberSimple cacheValue = memberCache.get(memberId);
        if (ObjUtil.isNotNull(cacheValue)) {
            return cacheValue;
        }
        MemberProfileMain profileMain = new QMemberProfileMain().id.eq(memberId).findOne();
        if (checkNull) {
            Assert.notNull(profileMain, "会员信息不存在");
        }
        MemberSimple memberSimple = BeanUtil.copyProperties(profileMain, MemberSimple.class);
        if (memberSimple.getFirmAttr().getPig() > 0) {
            memberSimple.getFirmAttr().setIsGetPig(false);
        } else {
            memberSimple.getFirmAttr().setIsGetPig(true);
        }
        if ((ObjUtil.isNull(profileMain.getClient())||ObjUtil.equals(profileMain.getClient(),"unknown"))||(ObjUtil.isNull(profileMain.getImei())||ObjUtil.equals(profileMain.getImei(),"unknown"))){
            Map<String, String> contextClient = LocalContextClient.get();
            profileMain.setClient(contextClient.get("client")).setImei(contextClient.get("imei"));
            profileMain.update();
        }
        Opt.ofNullable(memberSimple).ifPresent(x -> memberCache.put(memberId, x));
        return memberSimple;
    }

    public void addGuidelines(Long memberId, String msg) {
        MemberProfileMain profileMain = new QMemberProfileMain().id.eq(memberId).setMaxRows(1).findOne();
        if (ObjUtil.isNotNull(profileMain)) {
            //更新缓存
            cacheService.getMemberCache().put(memberId, BeanUtil.copyProperties(profileMain, MemberSimple.class));
            profileMain.setTutorial(msg).update();
        }
    }


    public PigGoods getDefaultGoods() {
        MemberSimple simple = readSimple(MemberAcl.getLoginId(), true);
        if (simple.getFirmAttr().getChecked() && !simple.getFirmAttr().getIsGetPig() && simple.getFirmAttr().getPig() >= 1) {
            return getPigGoods(simple.getFirmAttr().getPigGoodsCode());
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    public MemberMaterialPig addDefaultGoods() {
        PigGoods goods = getDefaultGoods();
        Assert.isFalse(ObjUtil.isNull(goods), "当前账号没有 企业猪仔");
        //查找猪仔等级
        PigLevel one = new QPigLevel().day.eq(goods.getDayNum()).breed.eq(goods.getBreed()).setMaxRows(1).findOne();
        PigLevelView levelView = BeanUtil.copyProperties(one, PigLevelView.class);
        //生成猪猪

        MemberMaterialPig pig = new MemberMaterialPig();
        String pigCode = IdUtil.getSnowflakeNextIdStr().substring(2, 9);
        pig.setCode(pigCode)
                .setTotalConsume(0)
                .setName(goods.getBreed().getName())
                .setStatus(PigStatus.WAIT)
                .setBreed(goods.getBreed())
                .setPigLevel(levelView)
                .setMember(new MemberView().setId(MemberAcl.getLoginId()))
                .setReserveFund(goods.getReserveFund())
                .insert();
        //生成改名卡
        if (goods.getMode().equals(PigstyKind.ALONE)) {
            Optional<PropsServe> serve = new QPropsServe().task.eq(ServeTask.RECHRISTEN).setMaxRows(1).findOneOrEmpty();
            serve.ifPresent(x -> {
                memberMaterialPropsRepository.add(new RMemberMaterialProps.EditBody().setIcon(x.getIcon()).setName(x.getName()).setCode(x.getCode()).setNumber(1).setMember(new MemberView().setId(MemberAcl.getLoginId())).setKind(PropsKind.L2).setDurable(0));
            });
        }
        //设置包月次数
        PropsComboView one1 = new QPropsComboView().isPack.eq(true).setMaxRows(1).findOne();
        batchService.addListPlan(null, one1, pig.getMember().getId(), pig.getId(), goods.getMonth() * 30);

        //生成工单
        pigOrderRepository.createAWorkOrder(new MemberPigView().setId(pig.getId()), null, PigOrderKind.L1, PigOrderStatus.ALLOCATED, new WorkOrder.EnterTheCircleBody().setDay(goods.getDayNum()).setMode(goods.getMode()).setId(pig.getId()));

        MemberProfileMain profileMain = new QMemberProfileMain().id.eq(MemberAcl.getLoginId()).setMaxRows(1).findOne();
        if (ObjUtil.isNotNull(profileMain)) {
            profileMain.getFirmAttr().setPig(NumberUtil.sub(profileMain.getFirmAttr().getPig(), Integer.valueOf(1)).intValue());
            profileMain.getFirmAttr().setIsGetPig(profileMain.getFirmAttr().getPig() < 0);
            profileMain.update();
        }
        return pig;
    }

    public PigGoods getPigGoods(String code) {
        return new QPigGoods().code.eq(code).setMaxRows(1).findOne();
    }

    public MemberProfileMain getOneById(Long memberId) {
        MemberProfileMain one = new QMemberProfileMain().id.eq(memberId).setMaxRows(1).findOne();
        Assert.notNull(one, "会员信息查询失败");
        return one;
    }

    @Async
    public void actionSignOut(Long memberId) {
        log.warn("正在进行会员账户注销程序");
        MemberProfileMain memberProfileMain = getOneById(memberId);
        memberProfileMain.setActivate(Boolean.FALSE).setRefreshToken(StrUtil.EMPTY).update();
        log.warn("TODO注销处理其他数据......");
    }

    /**
     * 修改会员昵称
     *
     * @param memberId 会员编号
     * @param nickName 会员新昵称
     */
    public void changeNickName(Long memberId, String nickName) {
        MemberProfileMain profileMain = getOneById(memberId);
        profileMain.setNickName(nickName).update();
        cacheService.getMemberCache().remove(memberId);
    }

    /**
     * 修改会员头像
     *
     * @param memberId 会员编号
     * @param avatar   会员头像
     */
    public void changeAvatar(Long memberId, String avatar) {
        MemberProfileMain profileMain = getOneById(memberId);
        profileMain.setAvatar(avatar).update();
        cacheService.getMemberCache().remove(memberId);

    }

    /**
     * 游戏账号和微信公众号绑定
     *
     * @param memberId 会员ID
     * @param wxMpId   公众号的openId
     * @return {@link String}
     */
    public String bindMpId(Long memberId, String wxMpId) {

        MemberProfileMain profileMain = getOneById(memberId);
        if (ObjUtil.isNull(profileMain)) {
            return "绑定失败：账号信息信息查询失败";
        }
        if (StrUtil.isNotBlank(profileMain.getWxMpId())) {
            return "绑定失败:当前认养账号已绑定过微信账号了!";
        }
        String oldRes = new QMemberProfileMain().wxMpId.eq(wxMpId).wxMpId.isNotNull()
                .select(QMemberProfileMain.Alias.id).setMaxRows(1).findSingleAttribute();
        if (StrUtil.isNotBlank(oldRes)) {
            return "绑定失败:当前微信账号已绑定过其他认养账号 请不要重复绑定!";
        }

        profileMain.setWxMpId(wxMpId).update();
        return "账号绑定成功:恭喜你成功绑定手机号码".concat(profileMain.getPhoneNumber()).concat("注册的认养账号！");
    }


}
